import java.util.Iterator;
import java.util.Set;
import java.util.HashSet;
import java.lang.Comparable;
import java.lang.Integer;
import java.lang.String;
import java.lang.Thread;
import java.lang.Runnable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;

public class Test {
    public <T extends Iterable> void printTuple(T t) {
        String str = "(";
        for (Object var : t) {
            if (var == null) {
                str += "null, ";
            } else {
                str += var.toString() + ", ";
            }
        }
        str += ")";
        System.out.println(str);
    }
    public void printArray(Object[] t) {
        String str = "(";
        for (int i = 0; i < t.length; i++) {
            if (t[i] == null) {
                str += "null, ";
            } else {
                str += t[i].toString() + ", ";
            }
        }
        str += ")";
        System.out.println(str);
    }
    public void testTuple() {
        System.out.println("testTuple...");
        TupleUtil.TupleFactory tfy = new TupleUtil.MyTupleFactory();

        TupleUtil.Tuple tp1 = tfy.newTuple(null, "abc", 123, 'y');
        System.out.println("---------------- tp1");
        printTuple(tp1);
        TupleUtil.Tuple tp2 = tp1.replace(1, 1000);
        System.out.println("---------------- tp2 = tp1.replace(1, 1000)");
        printTuple(tp2);
        Object[] tp3 = tp1.toArray();
        System.out.println("---------------- tp3 = tp1.toArray()");
        printArray(tp3);
        TupleUtil.Tuple tp4 = tfy.newTuple(null, "abc", 123, 'y');
        if (tp1.equals(tp4)) {
            System.out.printf("%s == %s\n", tp1.getClass().getName(), tp4.getClass().getName());
            printTuple(tp1);
            printTuple(tp4);
        } else {
            System.out.printf("%s <> %s\n", tp1.getClass().getName(), tp4.getClass().getName());
            printTuple(tp1);
            printTuple(tp4);
        }
        System.out.println("test hascode, result 1.");
        Map<Object,String> testMap = new HashMap<Object,String>();
        testMap.put(tp1, "1");
        System.out.println(testMap.get(tp4));

        Set set = new HashSet();
        set.add("abc");
        set.add(100);
        set.add(null);
        TupleUtil.Tuple tp6 = tfy.newTuple(set);
        System.out.println("---------------- tp6");
        printTuple(tp6);
    }

    public class Cat implements Comparable {
        Integer age;
        String name;

        @Override
        public String toString() {
            return "Cat [age=" + age + ", name=" + name + "]";
        }

        public Cat(int age, String name) {
            super();
            this.age = age;
            this.name = name;
        }
     
        @Override
        public int compareTo(Object o) {
            if (o instanceof Cat) {
                Cat p = (Cat) o;
                int i = this.age.compareTo(p.age);
                if (i == 0) {
                    return this.name.compareTo(p.name);
                }else {
                    return i;
                }
            }
            return 0;
        }
    }

    public class Dog implements Comparable {
        Integer age;
        String name;

        @Override
        public String toString() {
            return "Dog [age=" + age + ", name=" + name + "]";
        }

        public Dog(int age, String name) {
            super();
            this.age = age;
            this.name = name;
        }
     
         @Override
        public int compareTo(Object o) {
            if (o instanceof Dog) {
                Dog p = (Dog) o;
                int i = this.age.compareTo(p.age);
                if (i == 0) {
                    return this.name.compareTo(p.name);
                }else {
                    return i;
                }
            }
            return 0;
        }
    }
    public <T extends Comparable<T>> TupleUtil.ComparableTuple<T> createComparableTuple(T... arr) {
        if(arr == null) {
            throw new NullPointerException();
        }
        return new TupleUtil.MyCompareTuple(null, "a1", "b3", 10);
    }

    public void testCompareTuple() {
        System.out.println("testCompareTuple...");
        TupleUtil.ComparableTuple[] allItems = new TupleUtil.ComparableTuple[] {
            new TupleUtil.MyCompareTuple("ab", 11),
            new TupleUtil.MyCompareTuple("ab", 10, 123),
            new TupleUtil.MyCompareTuple("ab", 11, 123),
            new TupleUtil.MyCompareTuple("ab", null, 123)
        };
        System.out.println("----------------");
        for (TupleUtil.ComparableTuple item : allItems) {
            printTuple(item);
        }
        Arrays.sort(allItems);
        System.out.println("----------------");
        for (TupleUtil.ComparableTuple item : allItems) {
            printTuple(item);
        }

        TupleUtil.TupleFactory tfy = new TupleUtil.MyTupleFactory();
        TupleUtil.ComparableTuple[] allItems1 = new TupleUtil.ComparableTuple[] {
            tfy.newComparableTuple(null, "a1", "b3"),
            tfy.newComparableTuple(null, "a1", "b2"),
            tfy.newComparableTuple(null, new Cat(10, "10"), new Dog(21, "21"), new Cat(11, "11")),
            tfy.newComparableTuple(null, "a1", "b1", "c1"),
            tfy.newComparableTuple("10", "11")
        };
        System.out.println("----------------");
        for (TupleUtil.ComparableTuple item : allItems1) {
            printTuple(item);
        }
        Arrays.sort(allItems1);
        System.out.println("----------------");
        for (TupleUtil.ComparableTuple item : allItems1) {
            printTuple(item);
        }
        
        ArrayList carr = new ArrayList();
        carr.add("abc");
        carr.add(null);
        carr.add(20);
        TupleUtil.ComparableTuple cmptp6 = tfy.newComparableTuple(carr);
        System.out.println("---------------- cmptp6");
        printTuple(cmptp6);
    }
    public static void main(String[] args) {
        new Test().testTuple();
        new Test().testCompareTuple();
        new Test().testQ();
    }

    public void spent(QueueUtil.ConflatingQueue<String, Integer> kq) {
        try {
            while(!kq.isEmpty()) {
                QueueUtil.KeyedValue<String, Integer> item = kq.take();
                System.out.println("take: " + item.getKey() + " -> " + item.getValue());
            }
        }
        catch (InterruptedException e) {

        }
    }
    public void testQ() {
        System.out.println("queue test...");

        QueueUtil.ConflatingQueue<String, Integer> kq = new QueueUtil.KeyQueue<String, Integer>();
        for (int i = 1000; i < 1005; i++) {
            System.out.println("product z" + String.valueOf(i));
            kq.offer(new QueueUtil.KeyedValue<String, Integer>("z" + i, i));
        }
        // spent(kq);
        System.out.println("================");
        for (int i = 1000; i < 1005; i++) {
            kq.offer(new QueueUtil.KeyedValue<String, Integer>("z" + i, i+ 1000));
        }
        spent(kq);

        Thread[] tasks = new Thread[4];
        tasks[0] = new Thread(new Runnable(){
            public void run() {
                for (int i = 1000; i < 2000; i++) {
                    System.out.println("product zzz" + String.valueOf(i));
                    kq.offer(new QueueUtil.KeyedValue<String, Integer>("zzz" + i, i));
                }
            }
        });
        tasks[1] = new Thread(new Runnable(){
            public void run() {
                for (int i = 2000; i < 3000; i++) {
                    System.out.println("product xxxx" + String.valueOf(i));
                    kq.offer(new QueueUtil.KeyedValue<String, Integer>("xxxx" + i, i));
                }
            }
        });
        tasks[2] = new Thread(new Runnable(){
            public void run() {
                try {
                    while(true) {
                        QueueUtil.KeyedValue<String, Integer> item = kq.take();
                        System.out.println("take: " + item.getKey() + " -> " + item.getValue());
                    }
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        tasks[3] = new Thread(new Runnable(){
            public void run() {
                try {
                    while(true) {
                        QueueUtil.KeyedValue<String, Integer> item = kq.take();
                        System.out.println("take: " + item.getKey() + " -> " + item.getValue());
                    }
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        try {
            for (int i = 0; i < tasks.length; i++) {
                tasks[i].start();
            }
            for (int i = 0; i < tasks.length; i++) {
                tasks[i].join();
            }
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}